/*
 * LoaderOBJ.cpp
 *
 *  Created on: 09.07.2011
 *      Author: alki
 */

#define LOADEROBJ_TAGS
#include "LoaderOBJ.h"

LoaderOBJ::LoaderOBJ() {
}

LoaderOBJ::~LoaderOBJ() {
}

void LoaderOBJ::LoadFile(string filename,vector<Objekt> &objekte,MaterialManager &matman) {
	this->m_file.open(filename.c_str());
	if(!this->m_file.good())
		throw new Exception(NULL,__FILE__,__LINE__,"Fehler beim Öffnen der Datei","Datei nicht gefunden");
	this->m_matman=&matman;

	Objekt *object=NULL;
	int material=-1;
	int tex=-1;
	unsigned int verts=0;

	string line;
	while(!this->m_file.eof()) {
		TAG tag=(TAG)this->ReadTagLine(line);
		if(tag==mtllib) {
			this->ReadMaterial(line,filename);

/*			for(unsigned int i=0;i<this->m_materialnamen.size();i++) {
				cout << i << ": " << this->m_materialnamen[i] << endl;
			}*/
		}
		else if(tag==o) {
			if(object!=NULL) {
				this->CreateObject(object,verts);
				this->m_objekte.push_back(Objekt(*object));
				delete object;
				object=NULL;

				verts+=this->m_vertices.size();
				this->m_vertices.clear();
				this->m_surfaces.clear();
			}
			object=new Objekt;
		}
		else if(tag==v) {
			float x,y,z;
			sscanf(line.c_str(),"v %f %f %f",&x,&y,&z);
			this->m_vertices.push_back(Vektor(x,y,z));
		}
		else if(tag==f) {
			float a,b,c;
			sscanf(line.c_str(),"f %f %f %f",&a,&b,&c);

			SURFACE surf;
			surf.vertex.push_back(a);
			surf.vertex.push_back(b);
			surf.vertex.push_back(c);
			surf.material=material;
			surf.tex=tex;

			surf.u.push_back(0);
			surf.u.push_back(0);
			surf.u.push_back(0);
			surf.v.push_back(0);
			surf.v.push_back(0);
			surf.v.push_back(0);

			this->m_surfaces.push_back(surf);
		}
		else if(tag==usemtl) {
			string name=line.substr(7);
			material=-1;
			for(unsigned int i=0;i<this->m_materialnamen.size();i++) {
				if(name==this->m_materialnamen[i]) {
					material=this->m_matman->addMaterial(this->m_materialien[i]);
					break;
				}
			}
		}
	}
	if(object!=NULL) {
		this->CreateObject(object,verts);
		this->m_objekte.push_back(Objekt(*object));
		delete object;
		object=NULL;

		this->m_vertices.clear();
		this->m_surfaces.clear();
	}

	cout << this->m_materialien.size() << " Materialien geladen" << endl;
	cout << this->m_objekte.size() << " Objekte geladen" << endl;

	this->m_file.close();

	for(unsigned int i=0;i<this->m_objekte.size();i++)
		objekte.push_back(this->m_objekte[i]);
}

int LoaderOBJ::ReadTagLine(string &line) {
	getline(this->m_file,line);
	if(this->strbegins(line,"mtllib"))
		return mtllib;
	if(this->strbegins(line,"o"))
		return o;
	if(this->strbegins(line,"v"))
		return v;
	if(this->strbegins(line,"f"))
		return f;
	if(this->strbegins(line,"usemtl"))
		return usemtl;

	return NUL;
}

void LoaderOBJ::ReadMaterial(const string &line,const string &filename) {
	vector<string> split;
	this->strsplit(line,' ',split);

	vector<string> vpath;
	this->strsplit(filename,'/',vpath);
	string path;
	for(unsigned int i=0;i<vpath.size()-1;i++) {
		path.append(vpath[i]);
		path.append("/");
	}

	path.append(split[1]);

	ifstream matfile;
	matfile.open(path.c_str());

	Material *mat=NULL;
	string name;

	string matline;
	while(!matfile.eof()) {
		getline(matfile,matline);

		if(this->strbegins(matline,"newmtl")) {
			if(mat!=NULL) {
				this->m_materialien.push_back(Material(*mat));
				delete mat;
				mat=NULL;

				this->m_materialnamen.push_back(name);
			}
			mat=new Material();
			name=matline.substr(7);
		}
		else if(this->strbegins(matline,"Ka")) {
			float r,g,b;
			sscanf(matline.c_str(),"Ka %f %f %f",&r,&g,&b);
			mat->setLightAmbient(FARBE(r,g,b));
		}
		else if(this->strbegins(matline,"Kd")) {
			float r,g,b;
			sscanf(matline.c_str(),"Kd %f %f %f",&r,&g,&b);
			mat->setLightDiffus(FARBE(r,g,b));
		}
		else if(this->strbegins(matline,"Ke")) {
			float r,g,b;
			sscanf(matline.c_str(),"Ke %f %f %f",&r,&g,&b);
			mat->setLightEmissive(FARBE(r,g,b));
		}
		else if(this->strbegins(matline,"Ks")) {
			float r,g,b;
			sscanf(matline.c_str(),"Ks %f %f %f",&r,&g,&b);
			mat->setLightSpecular(FARBE(r,g,b));
		}
		else if(this->strbegins(matline,"Tf")) {
			float r,g,b;
			sscanf(matline.c_str(),"Tf %f %f %f",&r,&g,&b);
			float t=(r+g+b)/3;
			mat->setTransmission(t);
		}
		else if(this->strbegins(matline,"Rf")) {
			float r,g,b;
			sscanf(matline.c_str(),"Rf %f %f %f",&r,&g,&b);
			float t=(r+g+b)/3;
			mat->setReflexion(t);
		}
		else if(this->strbegins(matline,"Fs")) {
			float s;
			sscanf(matline.c_str(),"Fs %f",&s);
			mat->setSpecularFaktor(s);
		}
		else if(this->strbegins(matline,"Fd")) {
			float d;
			sscanf(matline.c_str(),"Fd %f",&d);
			mat->setDiffusFaktor(d);
		}
		else if(this->strbegins(matline,"Ns")) {
			unsigned int e;
			sscanf(matline.c_str(),"Ns %d",&e);
			mat->setSpecularExponent(e);
		}
		else if(this->strbegins(matline,"Ni")) {
			float n;
			sscanf(matline.c_str(),"Ni %f",&n);
			mat->setBrechung(n);
		}
	}

	matfile.close();

	if(mat!=NULL) {
		this->m_materialien.push_back(Material(*mat));
		delete mat;
		mat=NULL;

		this->m_materialnamen.push_back(name);
	}
}

void LoaderOBJ::CreateObject(Objekt *obj,unsigned int verts) {
	if(obj==NULL) {
		throw new Exception(NULL,__FILE__,__LINE__,"CreateObject fehlgeschlagen","kein Zielobjekt definiert!");
	}
	for(unsigned int s=0;s<this->m_surfaces.size();s++) {
		TRIANGLE tri;
		for(unsigned int v=0;v<this->m_surfaces[s].vertex.size();v++) {
			tri.points[v]=obj->getVertexCount();
			VERTEX vert;
			vert.pos=this->m_vertices[this->m_surfaces[s].vertex[v]-verts-1];
			vert.u=this->m_surfaces[s].u[v];
			vert.v=this->m_surfaces[s].v[v];
			vert.mat=-1;

			if(this->m_surfaces[s].material!=-1) {
				vert.mat=this->m_surfaces[s].material;
			}
			obj->AddVertex(VERTEX(vert));
		}
		obj->AddTriangle(tri);
	}
	obj->setRotation(0,0,0);
	obj->setPosition(0,0,0);
}
